package net.yla.smartbus.core.util;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.vip.vjtools.vjkit.time.DateFormatUtil;

import net.yla.smartbus.core.annotation.Empty;
import net.yla.smartbus.core.annotation.PojoCastToJson;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

import static java.util.stream.Collectors.toList;

/**
 * @author Handy Wong
 * @date 2020/1/20 15:53
 */
public class PojoJsonUtil {


    /**
     * 通过属性上注解获取json
     *
     * @param obj    实体对象
     * @param fields 前端需要的字段集合
     * @return
     */
    public static JSONObject writeJsonByField(Object obj, List<String> fields) {
        Map<String, Object> map = getFieldByMember(obj);
        JSONObject jsonObject = new JSONObject();
        if (null != fields && fields.size() > 0) {//存在前端指定字段
            for (String field : fields) {
                jsonObject.put(field, map.get(field));
            }
            return JSON.parseObject(jsonObject.toJSONString(jsonObject, SerializerFeature.DisableCircularReferenceDetect));
        } else {//不特定指定所需字段,返回所有被注解的字段
            return JSON.parseObject(JSONObject.toJSONString(new JSONObject(map), SerializerFeature.DisableCircularReferenceDetect));
        }
    }


    /**
     * 注解被用在get方法时输出格式化json
     *
     * @param obj    实体对象
     * @param fields 前端需要的字段集合
     * @return
     */
    public static JSONObject writeJsonByMethod(Object obj, List<String> fields) {
        Map<String, Object> map = getFiledByMethod(obj);
        JSONObject jsonObject = new JSONObject();
        if (fields != null && fields.size() > 0) {//存在前端指定字段
            for (String key : fields) {
                Object temp = map.get(key);
                jsonObject.put(key, temp);
            }
            return jsonObject;
        } else {//不特定指定所需字段,返回所有被注解的字段
            return new JSONObject(map);
        }

    }//writeJsonByMethod


    /**
     * 获取被PojoCastToJson注解的属性名称
     *
     * @param obj
     * @return
     */
    public static List<String> getAnnotatedFiled(Object obj) {
        List<String> list = null;
        Class clazz = obj.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        if (null != methods && methods.length > 0) {
            list = new LinkedList<>();
            for (Method method : methods) {
                //被该注解注解的方法对象
                if (method.isAnnotationPresent(PojoCastToJson.class)) {
                    //获取当前方法上所有的注解的注解
                    Annotation temp = method.getAnnotation(PojoCastToJson.class);
                    String name = ((PojoCastToJson) temp).value();
                    //将注解定义的Pojo对应的JSON字符串属性名称放入集合
                    list.add(name);
                }
            }
        }
        return list;
    }

    /**
     * 获取前端需要属性(字段)与该类被PojoCastToJson注解的属性(字段)交集
     *
     * @param annotatedFiled 被注解的属性
     * @param fields         前端所需要的属性
     * @return
     */
    public static List<String> getBeUsedFiled(List<String> annotatedFiled, List<String> fields) {
        List<String> list = null;
        if (annotatedFiled != null && fields != null) {
            list = annotatedFiled.stream().filter(item -> fields.contains(item)).collect(toList());
        }
        return list;
    }

    /**
     * 获取被PojoCastToJson注解注解到的方法集合
     *
     * @param obj
     * @return
     */
    public static List<Method> getAnnotatedMethods(Object obj) {
        Class clazz = obj.getClass();
        //可能存在被继承的父类
        Class superClass = clazz.getSuperclass();
        Method[] methods = clazz.getDeclaredMethods();
        Method[] superMethods = superClass.getDeclaredMethods();
        List<Method> result = null;
        if (null != methods && methods.length > 0) {
            result = new LinkedList<>();
            setAnnotatedMethods(methods,result);
            if(null!=superMethods){
                setAnnotatedMethods(superMethods,result);
            }
        }
        return result;
    }

    private static void setAnnotatedFields(Field[] fields, List<Field> list) {
        for (Field field : fields) {
            //打开私有属性
            field.setAccessible(true);
            if (field.isAnnotationPresent(PojoCastToJson.class)) {//该属性被该注解注解到
                list.add(field);
            }
        }
    }

    static void setAnnotatedMethods(Method[] methods, List<Method> list) {
        for (Method method : methods) {
            if (method.isAnnotationPresent(PojoCastToJson.class)) {
                list.add(method);
            }
        }
    }

    /**
     * 获取被PojoCastToJson注解到的属性
     *
     * @param obj
     * @return
     */
    public static List<Field> getAnnotatedFields(Object obj) {
        //本类
        Class clazz = obj.getClass();
        //可能存在的被继承父类
        Class superClass = clazz.getSuperclass();
        Field[] fields = clazz.getDeclaredFields();
        Field[] superFields = superClass.getDeclaredFields();
        List<Field> result = null;
        if (null != fields && fields.length > 0) {
            result = new LinkedList<>();
            setAnnotatedFields(fields, result);
            if (superFields != null && superFields.length > 0) {
                setAnnotatedFields(superFields, result);
            }
        }
        return result;
    }

    /**
     * (该注解被直接注解到属性上时)
     *
     * @param obj 当前表映射实体对象
     * @return 被注解到的Hash表集合
     */
    public static Map<String, Object> getFieldByMember(Object obj) {
        //获取被注解到的成员属性
        List<Field> fields = getAnnotatedFields(obj);
        Map<String, Object> map = new Hashtable<>();
        if (null != fields) {
            for (Field field : fields) {
                //打开私有属性访问权限
                field.setAccessible(true);
                Annotation temp = field.getAnnotation(PojoCastToJson.class);
                try {
                    String name = ((PojoCastToJson) temp).value();
                    Object value = field.get(obj);
                    if (java.util.Date.class == field.getType()) {
                        value = getDate((Date) value);
                    }
                    if (value == null) {
                        value = Empty.getInstance();
                    }
                    map.put(name, value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }


    /**
     * (注解使用在属性的get方法上时)
     *
     * @param obj 当前表映射实体类对象
     * @return 被PojoCastToJson注解到的Hash表集合
     */
    public static Map<String, Object> getFiledByMethod(Object obj) {
        Map<String, Object> map = new Hashtable<>();
        List<Method> list = getAnnotatedMethods(obj);
        if (list != null && list.size() > 0) {
            for (Method method : list) {
                Annotation temp = method.getAnnotation(PojoCastToJson.class);
                String name = ((PojoCastToJson) temp).value();
                String methodName = method.getName();
                if (methodName.indexOf("get") != -1) {//只在get方法时利用反射调用get方法获取属性值
                    try {
                        Object result;
                        result = method.invoke(obj);
                        if (result == null) {
                            result = Empty.getInstance();
                        }
                        if (java.util.Date.class == method.getReturnType()) {
                            result = getDate((Date) result);
                        }
                        map.put(name, result);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return map;
    }

    private static String getDate(Date date) {
        if (null != date) {
            return DateFormatUtil.formatDate("yyyy-MM-dd HH:mm:ss", date);
        }
        return "Sorry,date object was not found!";
    }


}//class
